import { v7 as uuid } from "uuid";
import AppError from "@/common/error";
import { getUserById, getUserByName, type User } from "@/data/users";
import cache from "@/services/cache";
import passwordEncoder from "@/services/passwords/encoders";

const TOKEN_TTL_SECONDS = 60 * 60 * 24 * 7; // 7 days

async function signToken(_user: User): Promise<string> {
  return uuid();
}

const toCacheKey = (token: string) => `app:auth:token:${token}`;

type LoginOptions = {
  username: string;
  password: string;
};

type LoginResult = {
  token: string;
  ttlSeconds: number;
  user: User;
};

export const login = async ({ username, password }: LoginOptions): Promise<LoginResult> => {
  const user = await getUserByName(username);
  if (!user) {
    throw AppError.unauthorized403("用户不存在");
  }

  const result = await passwordEncoder.verify(password, user.password);
  if (!result) {
    throw AppError.unauthorized403("用户名或密码错误");
  }

  const newToken = await signToken(user);
  await cache.set(toCacheKey(newToken), `${user.id}`, TOKEN_TTL_SECONDS);
  return {
    token: newToken,
    ttlSeconds: TOKEN_TTL_SECONDS,
    user,
  };
};

export const logout = async (token: string) => {
  await cache.delete(toCacheKey(token));
};

export const getMe = async (token: string): Promise<User> => {
  const idStr = await cache.get(toCacheKey(token));
  if (!idStr) {
    throw AppError.unauthenticated401();
  }

  const me = await getUserById(+idStr);
  if (!me) {
    throw AppError.unauthenticated401();
  }
  return me;
};
